package org.oimwrapper.connectors.internal;

import Thor.API.*;
import Thor.API.Operations.*;

import com.thortech.xl.crypto.*;
import com.thortech.util.logging.*;
import java.text.*;
import java.util.*;import org.oimwrapper.connectors.exceptions.*;

/**
 * This provides common functions for managing organizations.
 * 
 * THIS IS AN INTERNAL CLASS AND SHOULD NOT BE USED DIRECTLY.
 */
public final class OIMStandardUtilities {

	/**
	 * The default logger instance for this instance.
	 */
	private Logger logger;

	/**
	 * The property operations instance that backs this object.
	 */
	private tcPropertyOperationsIntf propertyOp;

	/**
	 * The help operations instance that backs this object.
	 */
	private tcHelpOperationsIntf helpOp;

	/**
	 * The default constructor.
	 * 
	 * @param ClassLogger The Logger used by the invoking class.
	 * @param PropertyOp The property operations utility used by the invoking class.
	 * @param HelpOp The help operations utility used by the invoking class.
	 */
	protected OIMStandardUtilities(Logger ClassLogger, tcPropertyOperationsIntf PropertyOp, tcHelpOperationsIntf HelpOp) {
		logger = ClassLogger;
		propertyOp = PropertyOp;
		helpOp = HelpOp;
	}

	/**
	 * Concatenates strings together.
	 *
	 * @param Input An ordered array of strings to combine.
	 * @return The combination of the strings.
	 */
	public String combineStrings(String[] Input) {
		String result = "";
		for (int i = 0; i < Input.length; i++) {
			result = result + Input[i];
		}
		return result;
	}

	/**
	 * Converts a timestamp (as retrieved from OIM).
	 *
	 * @param Input The date as retrieved from OIM.
	 * @param InputFormats The format string for the resulting date.
	 * @return The date string formated as per the specified format string.
	 * @exception Exception
	 */
	public long parseDate(String Input, String[] InputFormats) throws Exception {
		for (int i = 0; i < InputFormats.length; i++) {
			try {
				SimpleDateFormat dateFormat = new SimpleDateFormat(InputFormats[i]);
				return Input == null || Input.length() == 0 ? 0L : dateFormat.parse(Input).getTime();
			} catch (ParseException e) { ; }
		}
		throw new ParseException(Input, 0);
	}

	/**
	 * Converts a date to a given string format.
	 *
	 * @param Input The date.
	 * @param OutputFormat The format string for the resulting date.
	 * @return The date string formated as per the specified format string.
	 * @exception Exception
	 */
	public String formatDate(long Input, String OutputFormat) throws Exception {
		SimpleDateFormat dateFormat = new SimpleDateFormat(OutputFormat);
		return dateFormat.format(new Date(Input));
	}

	/**
	 * Returns the default date format used by OIM.
	 *
	 * @return The default date format used by OIM.
	 * @exception Exception
	 */
	public String getDefaultDateFormat() throws Exception {
		logger.debug("Entering standardUtilities.getDefaultDateFormat()");
		String result = propertyOp.getPropertyValue("XL.DefaultDateFormat");
		logger.debug("Exiting standardUtilities.getDefaultDateFormat()");
		return result;
	}
	
	/**
	 * Checks that the OIM system is running at least the specified version.  Throws a 
	 * {@link OIMNotSupportedOnThisVersionException} if the system version does not meet the specified 
	 * minimum.
	 *
	 * @param AtLeast The minimum version to allow.
	 * @exception Exception
	 */
	public void checkVersion(String AtLeast) throws Exception {
		if (!checkIfVersion(AtLeast)) {
			throw new OIMNotSupportedOnThisVersionException(AtLeast);
		}
	}

	/**
	 * Checks that the OIM system is running at least the specified version. 
	 *
	 * @param AtLeast The minimum version to allow.
	 * @return <code>true</code> if the current version of OIM is at least at the specified minimum,
	 *         or <code>false</code> if the current version of OIM is less the the minimum.
	 * @exception Exception
	 */
	public boolean checkIfVersion(String AtLeast) throws Exception {
		logger.debug("Entering standardUtilities.checkVersion()");
		boolean result = true;
		Map data = helpOp.getHelpAbout();
		logger.debug("OIM Version = " + (String) data.get("Version"));
		String[] version = ((String) data.get("Version")).split("\\.");
		String[] atLeast = AtLeast.split("\\.");
		for (int i = 0; i < atLeast.length && i < version.length; i++) {
			int actual = Integer.parseInt(version[i]);
			int required = Integer.parseInt(atLeast[i]);
			if (actual < required) {
				result = false;
				break;
			} else if (actual > required) {
				break;
			}
		}
		logger.debug("Exiting standardUtilities.checkVersion()");
		return result;
	}
	
	/**
	 * Encrypts data using the same mechanism as OIM.
	 * 
	 * @param Data The data to encrypt.
	 * @return The encrypted data.
	 * @exception Exception
	 */
	public String encrypt(String Data) throws Exception {
		logger.debug("Entering standardUtilities.encrypt()");
		String result = tcCryptoUtil.encrypt(Data, "DBSecretKey");
		logger.debug("Exiting standardUtilities.encrypt()");
		return result;
	}
	
	/**
	 * Decrypts data using the same mechanism as OIM.
	 * 
	 * @param Data The data to decrypt.
	 * @return The decrypted data.
	 * @exception Exception
	 */
	public String decrypt(String Data) throws Exception {
		logger.debug("Entering standardUtilities.decrypt()");
		String result = tcCryptoUtil.decrypt(Data, "DBSecretKey");
		logger.debug("Exiting standardUtilities.decrypt()");
		return result;
	}
	
	/**
	 * Prints a Map's data out for debugging.
	 * 
	 * @param Data The Map to print.
	 * @exception Exception
	 */
	public void printDebugDump(Map Data) throws Exception {
		if (logger.isDebugEnabled()) {
			synchronized(logger) {
				logger.debug("**************************************");
				for (Iterator iterator = Data.keySet().iterator(); iterator.hasNext(); ) {
					String key = (String) iterator.next();
					Object value = Data.get(key);
					logger.debug(" " + key + " = '" + (value == null ? "<null>" : value.toString()) + "'");
				}
				logger.debug("**************************************");
			}
		}
	}

	/**
	 * Prints an array of Map's data out for debugging.
	 * 
	 * @param Data The Map array to print.
	 * @exception Exception
	 */
	public void printDebugDump(Map[] Data) throws Exception {
		if (logger.isDebugEnabled()) {
			synchronized (logger) {
				logger.debug("**************************************");
				for (int i = 0; i < Data.length; i++) {
					for (Iterator iterator = Data[i].keySet().iterator(); iterator.hasNext(); ) {
						String key = (String) iterator.next();
						Object value = Data[i].get(key);
						logger.debug(" " + key + "[" + Integer.toString(i) + "] = '" + (value == null ? "<null>" : value.toString()) + "'");
					}
				}
				logger.debug("**************************************");
			}
		}
	}
	
	/**
	 * Prints a tcResultSet's data out for debugging.
	 * 
	 * @param Data The tcResultSet to print.
	 * @exception Exception
	 */
	public void printDebugDump(tcResultSet Data) throws Exception {
		if (logger.isDebugEnabled()) {
			synchronized (logger) {
				logger.debug("**************************************");
				for (int i = 0; i < Data.getRowCount(); i++) {
					Data.goToRow(i);
					String[] columns = Data.getColumnNames();
					for (int j = 0; j < columns.length; j++) {
						logger.debug(" " + columns[j] + "[" + Integer.toString(i) + "] = '" + Data.getStringValue(columns[j]) + "'");
					}
				}
				logger.debug("**************************************");
			}
		}
	}
	
	/**
	 * Prints a Map's data out for information.
	 * 
	 * @param Data The Map to print.
	 * @exception Exception
	 */
	public void printInfoDump(Map Data) throws Exception {
		if (logger.isInfoEnabled()) {
			synchronized (logger) {
				logger.info("**************************************");
				for (Iterator iterator = Data.keySet().iterator(); iterator.hasNext(); ) {
					String key = (String) iterator.next();
					Object value = Data.get(key);
					logger.info(" " + key + " = '" + (value == null ? "<null>" : value.toString()) + "'");
				}
				logger.info("**************************************");
			}
		}
	}

	/**
	 * Prints an array of Map's data out for information.
	 * 
	 * @param Data The Map array to print.
	 * @exception Exception
	 */
	public void printInfoDump(Map[] Data) throws Exception {
		if (logger.isInfoEnabled()) {
			synchronized (logger) {
				logger.info("**************************************");
				for (int i = 0; i < Data.length; i++) {
					for (Iterator iterator = Data[i].keySet().iterator(); iterator.hasNext(); ) {
						String key = (String) iterator.next();
						Object value = Data[i].get(key);
						logger.info(" " + key + "[" + Integer.toString(i) + "] = '" + (value == null ? "<null>" : value.toString()) + "'");
					}
				}
				logger.info("**************************************");
			}
		}
	}
	
	/**
	 * Prints a tcResultSet's data out for information.
	 * 
	 * @param Data The tcResultSet to print.
	 * @exception Exception
	 */
	public void printInfoDump(tcResultSet Data) throws Exception {
		if (logger.isInfoEnabled()) {
			synchronized (logger) {
				logger.info("**************************************");
				for (int i = 0; i < Data.getRowCount(); i++) {
					Data.goToRow(i);
					String[] columns = Data.getColumnNames();
					for (int j = 0; j < columns.length; j++) {
						logger.info(" " + columns[j] + "[" + Integer.toString(i) + "] = '" + Data.getStringValue(columns[j]) + "'");
					}
				}
				logger.info("**************************************");
			}
		}
	}
}